package org.zjt.chapter1.channel.handler;

import io.netty.channel.*;
import io.netty.util.ReferenceCountUtil;
import lombok.extern.slf4j.Slf4j;

import java.net.SocketAddress;

/**
 * Description:   出站数据
 *
 *  1、channelHandler 共享，可被添加多次到channelPipeline中。
 *
 *  2、池化出站丢弃资源并释放资源。
 *
 *      ReferenceCountUtil.release(msg);     // 释放一次引用。并不会直接删除。刷出后，才会删除该内容。
 *      promise.setSuccess();               // 通知信息已经处理完成。
 *
 *
 *  3、ChannelPromise   异步回调通知
 *
 *      作为ChannelFuture 的子类，ChannelPromise 也可以被分配用于异步通知的监听器
 *
 *      // 添加事件处理回调。
 *      promise.addListener((ChannelFutureListener) future -> log.info(future.isSuccess() ? " 注销成功" : "注销失败"));
 *
 *
 * @author juntao.zhang
 * Date: 2018-07-11 下午7:17
 * @see
 */
@Slf4j
public class MyChannelOutboundHandler extends ChannelOutboundHandlerAdapter {


    @Override
    protected void ensureNotSharable() {
        super.ensureNotSharable();
    }

    /**
     * ChannelHandlerAdapter 还提供了实用方法isSharable() 。如果其对应的实现被标注为Sharable ，那么这个方法将返回true ，表示它可以被添加到多个ChannelPipeline 中。
     * 可被多次添加。
     *
     * @return
     */
    @Override
    public boolean isSharable() {
        return super.isSharable();
    }

    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
        super.handlerAdded(ctx);
    }

    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
        super.handlerRemoved(ctx);
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {

        super.exceptionCaught(ctx, cause);
    }

    /**
     * 绑定网络端口事件
     * @param ctx
     * @param localAddress
     * @param promise
     * @throws Exception
     */
    @Override
    public void bind(ChannelHandlerContext ctx, SocketAddress localAddress, ChannelPromise promise) throws Exception {
        super.bind(ctx, localAddress, promise);
    }

    /**
     * 连接事件
     * @param ctx
     * @param remoteAddress
     * @param localAddress
     * @param promise
     * @throws Exception
     */
    @Override
    public void connect(ChannelHandlerContext ctx, SocketAddress remoteAddress, SocketAddress localAddress, ChannelPromise promise) throws Exception {
        super.connect(ctx, remoteAddress, localAddress, promise);
    }

    /**
     * 断开连接事件
     * @param ctx
     * @param promise
     * @throws Exception
     */
    @Override
    public void disconnect(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception {
        super.disconnect(ctx, promise);
    }

    /**
     * 连接关闭
     * @param ctx
     * @param promise
     * @throws Exception
     */
    @Override
    public void close(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception {
        super.close(ctx, promise);
    }

    /**
     * 注销
     *
     * @param ctx
     * @param promise
     * @throws Exception
     */
    @Override
    public void deregister(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception {

        /** 出站数据，增加操作事件，当注销成功后，会响应该事件 **/
        promise.addListener((ChannelFutureListener) future -> log.info(future.isSuccess() ? " 注销成功" : "注销失败"));

        super.deregister(ctx, promise);
    }

    /**
     * 读数据
     * @param ctx
     * @throws Exception
     */
    @Override
    public void read(ChannelHandlerContext ctx) throws Exception {
        super.read(ctx);
    }

    /**
     * 写数据
     * @param ctx
     * @param msg
     * @param promise
     * @throws Exception
     */
    @Override
    public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {

        /** 出站时候，丢弃并释放ByteBuf资源 **/
        ReferenceCountUtil.release(msg);
        promise.setSuccess();

        //super.write(ctx, msg, promise);
    }

    /**
     * 刷新数据事件
     * @param ctx
     * @throws Exception
     */
    @Override
    public void flush(ChannelHandlerContext ctx) throws Exception {
        super.flush(ctx);
    }
}
